﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Platform.Storage.Entity;

namespace Platform.Tests.Data.Generators
{
	internal class DGen
	{

		public static DGenBuilder<DataObjectContext> DbContext()
		{
			DataObjectContext db = new DataObjectContext();
			return new DGenBuilder<DataObjectContext>( db, () => db.SaveChanges() );
		}
	}

	public interface IDGenBuilder
	{
		void Complete();
	}

	public class DGenBuilder<TSource> : IDGenBuilder
	{
		public event EventHandler Completed;

		public DGenBuilder( TSource context )
			: this( context, null )
		//: this( context, ( IDGenBuilder )null )
		{ }

		//public DGenBuilder( TSource context, IDGenBuilder parent )
		//{
		//	this.Context = context;
		//	this.Parent = parent;
		//}

		public DGenBuilder( TSource context,  Action completeCallback )
		{
			this.Context = context;

			if ( completeCallback != null )
				this.Completed += ( sender, args ) => completeCallback();
			//this.Parent = parentBuilder;
			//this.CompleteCallback = completeCallback;
		}


		public TSource Context
		{ get; private set; }


		//public Action CompleteCallback
		//{ get; private set; }

		public IDGenBuilder Parent
		{ get; private set; }

		#region IDGenBuilder Members

		public virtual void Complete()
		{
			if ( this.Completed != null )
				this.Completed( this, EventArgs.Empty );
		}

		#endregion
	}

	public static class SequenceBuilder
	{
		private static long sequence = 1;


		public static long NextNumber( this IDGenBuilder builder )
		{
			return Interlocked.Increment( ref sequence );
		}
	}

	public static class RandomBuilder
	{

		public static DGenBuilder<Random> Random( this IDGenBuilder parent )
		{
			return new DGenBuilder<Random>( new Random() );
		}

		public static string PropertyName( this DGenBuilder<Random> builder )
		{
			return String.Format( "Prop{0}", builder.Context.Next( 0, 100000 ) );
		}

		public static string Text( this DGenBuilder<Random> builder )
		{
			return builder.Text( 20 );
		}

		public static string Text( this DGenBuilder<Random> builder, int size )
		{
			char[] content = new char[ size ];

			for ( int index = 0; index < size; index++ )
				content[ index ] = ( char )builder.Context.Next( ( int )'a', ( int )'Z' );

			return new String( content );
		}
	}

	internal static class FieldValueBuilder
	{

		public static DGenBuilder<FieldValue> FieldValue( this DGenBuilder<DataObjectContext> db )
		{
			FieldValue field = new FieldValue( db.Random().PropertyName(), db.NextNumber().ToString() );

			field.TextValue = db.Random().Text( 50 );

			return new DGenBuilder<FieldValue>( field, () => db.Complete() );
		}

	}


	public static class DGenBuilderExtensionMethods
	{

		public static DGenBuilder<TEntity> Set<TEntity>( this DGenBuilder<TEntity> builder, Action<TEntity> values )
		{
			if ( values != null )
				values( builder.Context );

			return builder;
		}

		public static DGenBuilder<TEntity> Set<TEntity, TValue>( this DGenBuilder<TEntity> builder, Expression<Func<TEntity, TValue>> getter, TValue value )
		{
			string propertyName = getter.GetPropertyName();
			PropertyInfo property = typeof( TEntity ).GetProperties().FirstOrDefault( p => p.Name == propertyName );

			if ( property == null )
				throw new InvalidOperationException();

			property.SetValue( builder.Context, value );
			return builder;
		}
	}

	//public static class FieldValueBuilder 
	//{

	//	public static DGenBuilder<FieldValue>()
	//{
	//}
	//}
}
